package pe.edu.sistemas.sisdiho.services;

import java.sql.Date;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import pe.edu.sistemas.sisdiho.entities.Asistencia;
import pe.edu.sistemas.sisdiho.entities.CursoPeriodo;
import pe.edu.sistemas.sisdiho.entities.Docente;
import pe.edu.sistemas.sisdiho.entities.HorarioClase;
import pe.edu.sistemas.sisdiho.entities.Motivo;
import pe.edu.sistemas.sisdiho.entities.Periodo;
import pe.edu.sistemas.sisdiho.entities.Recuperacion;
import pe.edu.sistemas.sisdiho.entities.RegistroRecuperacion;
import pe.edu.sistemas.sisdiho.repositories.AsistenciaRepository;
import pe.edu.sistemas.sisdiho.repositories.CursoPeriodoRepository;
import pe.edu.sistemas.sisdiho.repositories.DocenteRepository;
import pe.edu.sistemas.sisdiho.repositories.HorarioClaseRepository;
import pe.edu.sistemas.sisdiho.repositories.MotivoRepository;
import pe.edu.sistemas.sisdiho.repositories.PeriodoRepository;
import pe.edu.sistemas.sisdiho.repositories.RecuperacionRepository;

@Service
@Transactional
public class RecuperacionService {

	@Autowired
	private AsistenciaRepository asistenciaRepository;
	@Autowired
	private HorarioClaseRepository horarioClaseRepository;
	@Autowired
	private DocenteRepository docenteRepository;
	@Autowired
	private PeriodoRepository periodoRepository;
	@Autowired
	private CursoPeriodoRepository cursoPeriodoRepository;
	
	@Autowired
	private RecuperacionRepository recuperacionRepository;	
	@Autowired
	private MotivoRepository motivoRepository;
	
	@Autowired
	private HorarioClaseService horarioClaseService;

	// 0-INASISTENCIA ;1-TARDANZA ; 2-INCOMPLETO; 3-ASISTIO
	private int encontroAsistencia; 
	
	/***
	 * Obtiene faltas,tardanza, e Horas incompletas para su posterior recuperacion
	 * 
	 * @param idDocente
	 * @param escuela
	 * @return
	 */
	public ArrayList<RegistroRecuperacion> ObtenerFaltasxDocente(int idDocente,int escuela) {
		ArrayList<RegistroRecuperacion> registros = new ArrayList<RegistroRecuperacion>();
		CursoPeriodo curso;
		List<Asistencia> auxAsistencias;
		Asistencia auxAsistencia;
		List<HorarioClase> horarios ;
		List<Recuperacion> recuperaciones ;
		Map<Integer, List<HorarioClase>> horariosMap;
		
		Calendar fechaActual = Calendar.getInstance();  //Calendar :HOY
		Calendar fechaModif = Calendar.getInstance(); //Calendar: fecha que itera
		Periodo p = periodoRepository.obtenerUltimoPeriodo();
		Docente docente=docenteRepository.obtenerDocentexID(idDocente);
		Date hoy=retornarSQLDate(fechaActual); //SQLDATE: HOY 
		fechaModif.setTime(fechaInicio(fechaActual, p)); // desde que dia empieza a iterar
		horariosMap=horarioClaseService.obtenerHorariosOrdenadosEnDiasxDocentexPeriodoxEscuela(idDocente, escuela,p.getNombre());
		int dia;
		
		while (fechaModif.before(fechaActual)) { //Hasta que no sea hoy
			dia = fechaModif.get(Calendar.DAY_OF_WEEK) - 1;
			horarios= horariosMap.get(dia);
			if(horarios!= null){
				Date fechaLim = fechaLimite(fechaModif);
				for(HorarioClase horarioClase : horarios){
					auxAsistencia = asistenciaRepository.obtenerAsistenciaxFechayIdHorario(
										retornarSQLDate(fechaModif), horarioClase.getIdHorarioClase());
					RegistroRecuperacion recup = new RegistroRecuperacion();
					curso = cursoPeriodoRepository.obtenerCursosxIdGrupo(horarioClase.getIdGrupo());
					
					
					recup.setFecha(this.retornarSQLDate(fechaModif).toString());
					recup.setCurso(curso.getNombre());
					recup.setTipo(horarioClase.getHorarioClaseTipo());
					recup.setFechaLimite(fechaLim.toString());
					recup.setIdHorario(horarioClase.getIdHorarioClase());
					recup.setCode(docente.getCodigo());
					recup.setName(docente.getapMaterno().toUpperCase()+" "
								+docente.getapPaterno().toUpperCase()+" "
								+docente.getNombre());
					
					if(auxAsistencia != null){ //si existe asistencia, se verifica la tardanza o si es incompleto
						int minDeudaFinal=this.minutosDeuda(horarioClase, auxAsistencia);
						recup.setMinutosDeuda(minDeudaFinal);
						recup.setTipoDeuda(this.retornaTipofalta());
						recup.setEstado("-");
						System.out.println("RECUPERACIONES "+recup.getTipoDeuda()+" "+recup.getIdHorario());
					}else{//Falto
						encontroAsistencia=0;
						recup.setTipoDeuda(this.retornaTipofalta());
						recuperaciones= recuperacionRepository.obtenerRecuperacionesxFechaxHorario(
													horarioClase.getIdHorarioClase(), retornarSQLDate(fechaModif));
						recup.setMinutosDeuda(difMinutos(horarioClase.getHoraInicio(), horarioClase.getHoraFin()));
						if(recuperaciones.size()>0){ //Existe recuperacion (puede recuperar en varios dias-proximamente)
							recup.setFechaProgramada(recuperaciones.get(0).getFechaRecuperacion().toString());
							//RECUPERACION ESTADO  0-PROGRAMADO 1-EN CURSO 2-RECUPERADO
							if(recuperaciones.get(0).getEstado()==1){
								recup.setEstado("EN CURSO");
							}
							if(recuperaciones.get(0).getEstado()==0){
								recup.setEstado("PROGRAMADO");
							}
							if(recuperaciones.get(0).getEstado()==2){
								recup.setEstado("RECUPERADO");
								recup.setHoraFin(recuperaciones.get(0).getHoraFinReal().toString());
								recup.setHoraInicio(recuperaciones.get(0).getHoraInicio().toString());
							}
							if(recuperaciones.get(0).getFechaRecuperacion().before(hoy)){
								recup.setEstado("NO RECUPERADO");
							}
						}else{ //No lo ha recuperado
							recup.setEstado("NO PROGRAMADO");
						}
					}
					if(encontroAsistencia!=3)
						registros.add(recup);
				}//end for
			}
			fechaModif.add(Calendar.DAY_OF_MONTH, 1);
		}//end while
		
		return registros;
	}
	
	public int difMinutos(Time x,Time y){
		int a=x.getHours()*60+x.getMinutes();
		int b=y.getHours()*60+y.getMinutes();
		return b-a;
	}
	
	public String retornaTipofalta(){
		if(encontroAsistencia==1)
			return "TARDANZA";
		if(encontroAsistencia==2)
			return "INCOMPLETO";
		if(encontroAsistencia==3)
			return "ASISTIO";
		if(encontroAsistencia==0)
			return "INASISTENCIA";
		return "";
	}
	
	public int minutosDeuda(HorarioClase horario,Asistencia asistencia){
		 
         Time horaInicioMarcada = asistencia.getHoraIngreso();
         Time horaFinMarcada = asistencia.getHoraSalida();
         Time horaInicioReal = horario.getHoraInicio();
         Time horaFinReal = horario.getHoraFin();
         int minutosDeudaTardanza=0,minutosDeudaFinal=0,minutosDeudaSalidaAntes=0;
         int difMinutosTardanza = difMinutos(horaInicioReal,horaInicioMarcada); 
         int difMinutosSalidaAntes = difMinutos(horaFinMarcada,horaFinReal); 
         encontroAsistencia=0;
         if (horaInicioMarcada.compareTo(horaFinMarcada) == 0) {//Si tiene misma hora de entrada y salida se considera solo su tardanza
             
             if (difMinutosTardanza > 15) {//Si la diferencia de minutos es mayor a 15 minutos se considera tardanza y guardamos los minutos tardes
                 minutosDeudaTardanza = difMinutosTardanza - 15;
                 minutosDeudaFinal = difMinutosTardanza ;
                 encontroAsistencia = 1;
             } else {//Al lo considerar salida, no debe nada
                 encontroAsistencia = 3;
             }
         } else {//Si hay marcacion de salida veremos la tardanza y si salio antes
             if (difMinutosTardanza > 15) {//Si la diferencia de minutos es mayor a 15 minutos se considera tardanza y guardamos los minutos tardes
                 minutosDeudaTardanza = difMinutosTardanza;
                 encontroAsistencia = 1;
             }
             if (difMinutosSalidaAntes > 5) {//Si es mayor a lo minimo que pudo marcar entonces salio antes
                 //guardamos los minutos deuda
                 minutosDeudaSalidaAntes = difMinutosSalidaAntes - 5;
                 encontroAsistencia = 2;
             }
             if (encontroAsistencia == 0) {
                 encontroAsistencia = 3;//no debe nada
             }
             minutosDeudaFinal = minutosDeudaTardanza + minutosDeudaSalidaAntes;
         }
		return minutosDeudaFinal;
	}
	
	// Map<Integer, List<HorarioClase>>
	

	
	public Map<String, Object> verificarCruce(int idDocente, Date fecha, Time hInicio,
			Time hFin) {
		Map<String, Object> m = new HashMap<String, Object>();
		
		ArrayList<HorarioClase> horarios = new ArrayList<HorarioClase>();
		ArrayList<Recuperacion> recuperaciones = new ArrayList<Recuperacion>();
		
		Periodo p = periodoRepository.obtenerUltimoPeriodo();
		
		Calendar x = Calendar.getInstance();
		x.setTime(fecha);
		int dia = x.get(Calendar.DAY_OF_WEEK) - 1;
		
		horarios = (ArrayList<HorarioClase>) horarioClaseRepository
				.obtenerHorariosCrucexDiaxDocentexPeriodo(idDocente, dia,
						hInicio, hFin, p.getNombre());
		recuperaciones = (ArrayList<Recuperacion>) recuperacionRepository
				.obtenerRecuperacionesCrucesxFecha(idDocente, fecha, hInicio,
						hFin, p.getNombre());
		if (horarios.size() > 0)
			m.put("H",horarios.get(0));
		if (recuperaciones.size()>0)
			m.put("R", recuperaciones.get(0));
		System.out.println("CRUCE HORARIOS + " + m.containsKey("H"));
		System.out.println("CRUCE RECUPERACIONES+ " + m.containsKey("R"));
		return m;
	}
	
	public Recuperacion obtenerRecuperacion (int idHorario,Date fa){
		ArrayList<Recuperacion> recuperaciones =new ArrayList<Recuperacion>();
		recuperaciones=(ArrayList<Recuperacion>) recuperacionRepository.obtenerRecuperacionesxFechaxHorario(idHorario,fa);
		Recuperacion r =new Recuperacion();
		r=recuperaciones.get(0);
		return r;
	}
	
	public void modificarRecuperacion(int idRec, Date fecha, Time hInicio, Time hFin,int idMotivo,String aula,String obs){
		recuperacionRepository.modificarRecuperacion( idRec,  fecha, hInicio,  hFin, idMotivo,aula,obs);
	}
	
	
	public  boolean motivoValido(String valor,int motivo){
		//MOTIVO = 1 ES SALUD 
		//SI EL MOTIVO ES DISTINDO A ENFERMEDAD  SE DEBE ESPECIFICAR ( NO DEBE SER VACIO)
		return (!valor.trim().equals("") || motivo == 1);
	}
	
	public String obtenerDia(int dia) {
		switch(dia){
		case 1: return "LUNES";
		case 2: return "MARTES";
		case 3: return "MIERCOLES";
		case 4: return "JUEVES";
		case 5: return "VIERNES";
		case 6: return "SABADO";
		case 7: return "DOMINGO";
		default: return "NN";
		}
	}
	Date fechaInicio(Calendar f, Periodo p) {
		int mes = f.get(Calendar.MONTH);// 0-11
		int annio = f.get(Calendar.YEAR);
		int dia = f.get(Calendar.DAY_OF_MONTH);
		Date inicioCalculado;
		if (mes <= 0) {
			mes = 12;
			annio--;
		}
		if (dia > 8 && dia < 24) {
			inicioCalculado = Date
					.valueOf(retornaCadenaFecha(annio, mes, "24"));
			System.out.println("*FECHA INICIO CICLO* + " + inicioCalculado);
		} else {
			if(dia>=24){
				if (mes == 12) {
					mes = 1;
				}else{
					mes++;//mes actual
				}
			}
			inicioCalculado = Date
					.valueOf(retornaCadenaFecha(annio, mes, "09"));
			System.out.println("**FECHA INICIO CICLO** + " + inicioCalculado);
		}

		Date inicioCiclo = Date.valueOf(p.getFechaInicio());
		System.out.println("FECHA INICIO CICLO + " + inicioCiclo);
		if (inicioCalculado.before(inicioCiclo))
			return inicioCiclo;
		return inicioCalculado;
	}

	Date fechaLimite(Calendar c) {
		int mes = c.get(Calendar.MONTH);// 0-11
		mes++;
		int annio = c.get(Calendar.YEAR);
		int dia = c.get(Calendar.DAY_OF_MONTH);
		Date fecha;
		if (dia > 8 && dia < 24) {
			mes = mes + 1;
			fecha = Date.valueOf(retornaCadenaFecha(annio, mes, "08"));
		} else {
			if (dia >= 24) {
				mes = mes + 1;
			}
			fecha = Date.valueOf(retornaCadenaFecha(annio, mes, "23"));
		}
		Date finCiclo = this.obtenerFinCiclo();
		if(fecha.after(finCiclo)){
			fecha =finCiclo;
		}
		return fecha;

	}

	// funcion extra 
	//a partir de un Calendar
	public Date retornarSQLDate(Calendar c) {
		int mes = c.get(Calendar.MONTH);// 0-11
		mes++;
		int annio = c.get(Calendar.YEAR);
		int dia = c.get(Calendar.DAY_OF_MONTH);
		if (dia < 10) {
			return Date.valueOf(retornaCadenaFecha(annio, mes, "0" + dia));
		} else {
			return Date.valueOf(retornaCadenaFecha(annio, mes, "" + dia));
		}

	}
	
	//a partir de un util.date
	public Date retornarSQLDate(java.util.Date f){
		SimpleDateFormat fechaFormato = new SimpleDateFormat("yyyy-MM-dd");
		Date fecha = Date.valueOf(fechaFormato.format(f));
		return fecha;
	}
	
	//a partir de un String  yyyy-MM-dd
	public Date retornarSQLDate(String c){
		Date fecha = Date.valueOf(c);
		return fecha;
	}

	String retornaCadenaFecha(int annio, int mes, String dia) {
		if (mes < 10) {
			return "" + annio + "-0" + mes + "-" + dia;
		} else {
			return "" + annio + "-" + mes + "-" + dia;
		}
	}
	
	public ArrayList<Motivo> obtenerMotivos (){
		//tipo 1 para recuperacion
		return (ArrayList<Motivo>) motivoRepository.obtenerMotivos(1);
	}
	
	public void insertarRecuperacion(int idHorarioClase,int idMotivo,Date fechaRec,
			Date fechaAusente,String Aula,Time horaInicio,Time horaFin,String obs,int estado){
		recuperacionRepository.insertarRecuperacion(idHorarioClase,
				idMotivo, 
				fechaRec,
				fechaAusente,
				Aula,
				horaInicio,
				horaFin,
				obs,
				estado);
	}
	
	public Date obtenerFinCiclo(){
		Periodo p = periodoRepository.obtenerUltimoPeriodo();
		return this.retornarSQLDate(p.getFechaFin());
	}
	
	public Recuperacion obtenerRecuperacionxId(int idRecuperacion){
		return recuperacionRepository.obtenerRecuperacionxId(idRecuperacion);
	}
}
